﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using VMS.FTS.APPPUSH.Log;
using VMS.FTS.APPPUSH.Device;
using VMS.FTS.APPPUSH.VmsCenter;
using System.IO;
using VMS.FTS.APPPUSH.Utils.Security.Cryptor;
using System.Threading;
using VMS.FTS.APPPUSH.Utils.Security.Authenticator;
using System.Reflection;

namespace VMS.FTS.APPPUSH.LETIDEVICES
{
    /// <summary>
    /// Leti device class
    /// </summary>
    public class LETIDevice : VMSDevice
    {
        public const int PACKAGE_TIMEOUT = 15000;

        TcpClient _client;
        [XmlIgnore]
        public TcpClient Client 
        { 
            get { return _client; } 
            set {
                _client = value;
                _client.SendTimeout     = PACKAGE_TIMEOUT;
                _client.ReceiveTimeout  = PACKAGE_TIMEOUT;
            } 
        }

        private List<VMSLayout> _layouts;
        [XmlArray("Layouts")]
        [XmlArrayItem("Layout")]
        public List<VMSLayout> Layouts
        {
            get { return _layouts; }
            set { _layouts = value; }
        }

        public VMSLayout getLayout(int p)
        {
            if (_layouts != null)
                return _layouts.Find(layout => layout.ID == p);

            return null;
        }
        public LETIDevice()
            : base()
        {
            // TODO: Complete member initialization
            LOG_TAG = this.GetType().Name;
            mActivePage = 1;
            LOG(MethodBase.GetCurrentMethod().Name, "LETI Device init successfully", LOG_LEVEL.INFO);
        }

        public LETIDevice(VMSDevice dev):base(dev)
        {
            // TODO: Complete member initialization
            LOG_TAG = "LETI Device";
            mActivePage = 1;
            LOG(MethodBase.GetCurrentMethod().Name, "LETI Device init successfully", LOG_LEVEL.INFO);
            
        }

        public ushort mActivePage;

        #region | Override methods |
        public override void open(object o)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            
            _client = (TcpClient)o;
            if (_client == null)
            {
                Status.Connected = false;
                throw new NotSupportedException("Leti device will be openned with tcpclient only");
            }

            try
            {
                Status.Connected = true;
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                Status.Connected = false;
            }
        }

        public override void close()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            // Disconnect client
            if (_client != null && _client.Connected)
            {
                _client.Client.Disconnect(false);
            }
            // reset to null
            _client = null;
            // update status
            Status.Connected = false;
        }

        public override bool ProcessCommand(VmsCommand command)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;
            if (command.GetType() == typeof(VmsControlCommand))
            {
                ProcessControlCommand((VmsControlCommand)command);
            }
            else if (command.GetType() == typeof(VmsSystemCommand))
            {
                ProcessSystemCommand((VmsSystemCommand)command);
            }
            return true;
        }

        private bool ProcessSystemCommand(VmsSystemCommand vmsSystemCommand)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;
            DEVICE_RESPONSE ret = DEVICE_RESPONSE.ERROR;
            switch (vmsSystemCommand.CommandType)
            {
                case VmsSystemCommandEnum.COMMAND_CAPTURE_SCREEN:
                    ret = this.CaptureScreen();
                    break;
                case VmsSystemCommandEnum.COMMAND_CHECK_LED:
                    ret = this.CheckLed();
                    break;
                case VmsSystemCommandEnum.COMMAND_CLEAR_SCREEN:
                    ret = this.ClearScreen();
                    break;
                case VmsSystemCommandEnum.COMMAND_GET_INFO:
                    //ret = Client.SendInfo(dev.Info);
                    break;
                case VmsSystemCommandEnum.COMMAND_GET_STATUS:

                    break;
                case VmsSystemCommandEnum.COMMAND_REBOOT:
                    ret = this.Reboot();
                    break;
                case VmsSystemCommandEnum.COMMAND_SCAN_LED:
                    ret = this.ScanLed();
                    break;
                case VmsSystemCommandEnum.COMMAND_UPDATE_FIRMWARE:
                case VmsSystemCommandEnum.COMMAND_UPDATE_FONT:
                default:
                    //TODO: add function here
                    break;
            }
            return ret == DEVICE_RESPONSE.SUCCESS;
        }

        private bool ProcessControlCommand(VmsControlCommand command)
        {
            // validate command
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;
            ushort LayoutID = 1;
            foreach (VmsCommandPayload payload in command.Payloads)
            {
                if (payload.GetType() != typeof(VmsControlCommandPayload))
                    continue;
                VmsControlCommandPayload pl = (VmsControlCommandPayload)payload;
                // page ID = layout ID
                ushort pageID = (ushort)pl.LayoutId;
                // Popup ID
                ushort popupID = (ushort)pl.PopupId;

                var page = this.getLayout( pageID);//.DeepClone();
                if (page == null)
                {
                    // Request layout from server here
                    throw new VMSLayoutNotFoundException(pageID);
                }
                // check if popup is available in pages
                VmsPopup popup = page.findPopup((ushort)pl.PopupId);
                if (popup == null)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Popup " + pl.PopupId + " not avaible ", LOG_LEVEL.ERROR);
                    return false;
                }

                int index = 0;

                foreach (VmsPlaylistItem imgItem in pl.Playlist.Items)
                {
                    if (popup.GetType() == typeof(PlaylistPopup) &&
                        imgItem.GetType() == typeof(VmsImagePlaylistItem))
                    {

                        /*
                        PlaylistPopup plPopup = (PlaylistPopup)popup;
                        plPopup.Images[index].ImageCode = (ushort)((VmsImagePlaylistItem)imgItem).ImageID;
                        plPopup.Images[index].Delay = (ushort)imgItem.Duration;
                        plPopup.Images[index].Effect = (EFFECT)imgItem.Effect;
                        bool ret = this.UpdateImage(pageID, popupID,
                                                plPopup.Images[index].PlayOrder,
                                                plPopup.Images[index]);
                         * */
                    }
                    else if (popup.GetType() == typeof(TextPopup) &&
                        imgItem.GetType() == typeof(VmsTextPlaylistItem) &&
                        pl.Playlist.Items.Length == 1)
                    {
                        TextPopup textPopup = (TextPopup)popup;
                        textPopup.Content = ((VmsTextPlaylistItem)imgItem).Text;
                        DEVICE_RESPONSE ret = this.UpdatePopup(pageID, popupID, popup);
                    }
                    else
                    {
                        LOG(MethodBase.GetCurrentMethod().Name, "Currently don't support " + popup.GetType(), LOG_LEVEL.DEBUG);
                        continue;
                    }

                    System.Threading.Thread.Sleep(2000);
                    // force device to update image
                    index++;
                }
                LayoutID = (ushort)pl.LayoutId;
                //bool ret = dev.UpdatePage();
            }
            System.Threading.Thread.Sleep(2000);
            if (this.mActivePage != LayoutID)
            {
                DEVICE_RESPONSE ret1 = this.ActivePage(LayoutID);
                if (ret1 == DEVICE_RESPONSE.SUCCESS)
                    this.mActivePage = LayoutID;
            }
            return true;
        }

        string getCommandInfo(VmsCommand cmd)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("\n{0,10}Command Info:\n{1,15}{2}\n{3,15}{4}", "",
                "ID: ", cmd.Id,
                "VMS ID: ", cmd.VmsId
                );

            if (cmd.GetType() == typeof(VmsSystemCommand))
                return sb.ToString();
            foreach (VmsCommandPayload payload in cmd.Payloads)
            {
                if (payload.GetType() == typeof(VmsControlCommandPayload))
                {
                    VmsControlCommandPayload p = (VmsControlCommandPayload)payload;
                    sb.AppendFormat("\n{0,20}{1,3}{2,15}{3}{4,15}{5}",
                        "Layout ID: ", p.LayoutId,
                        "Popup ID: ", p.PopupId,
                        "Playlist ID: ", p.Playlist.Id);

                    foreach (VmsPlaylistItem item in p.Playlist.Items)
                    {
                        if (item.GetType() == typeof(VmsImagePlaylistItem))
                        {
                            sb.AppendFormat("\n{0,25}ImageID: {1} Effect: {2} Duration: {3}", "",
                                ((VmsImagePlaylistItem)item).ImageID,
                                ((VmsImagePlaylistItem)item).Effect,
                                ((VmsImagePlaylistItem)item).Duration);
                        }
                    }
                }
            }
            return sb.ToString();
        }

        private bool DeviceReady()
        {
            if (!this.Status.Connected || _client == null || !_client.Connected)
            {
                LOG(MethodBase.GetCurrentMethod().Name, "Device not connected!", LOG_LEVEL.ERROR);
                return false;
            }
            return true;
        }

        public override bool UpdateDeviceStatus()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_GET_STATUS;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (readCount == 8 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_GET_STATUS)
                {
                    byte[] status = receivedBuffer.Skip(2).ToArray();
                    string hex = BitConverter.ToString(status);
                    hex = hex.Replace("-", " 0x");
                    hex = "0x" + hex;
                    LOG(MethodBase.GetCurrentMethod().Name, "Device status: " + hex, LOG_LEVEL.DEBUG);
                    
                    return true;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: " + receivedBuffer[0] +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + receivedBuffer[1] +
                            " ===> Expected:  CMD_GET_STATUS(" +
                            COMMAND.CMD_GET_STATUS + ")",
                        LOG_LEVEL.ERROR);
                    return false;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return false;
            }
        }

        /// <summary>
        /// Update current image
        /// </summary>
        /// <param name="objList"></param>
        public bool UpdateImage(params object[] objList)
        {
            if (objList.Length != 4)
                return false;

            try
            {
                ushort pageID = (ushort)objList[0];
                ushort popupID = (ushort)objList[1];
                byte playOrder = (byte)objList[2];
                VmsPopupImage image = (VmsPopupImage)objList[3];
                return UpdateImageToPlaylist(pageID, popupID, playOrder, image) == DEVICE_RESPONSE.SUCCESS;
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
            return true;
        }

        /// <summary>
        /// Update current image
        /// </summary>
        /// <param name="objList"></param>
        public bool UpdatePopup(params object[] objList)
        {
            if (objList.Length != 3)
                return false;

            try
            {
                ushort pageID = (ushort)objList[0];
                ushort popupID = (ushort)objList[1];
                VmsPopup popup = (VmsPopup)objList[2];
                return SendUpdatePopupCmd(pageID, popupID, popup);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
            return true;
        }

        public bool UpdatePage(params object[] objList)
        {
            return true;  
        }

        private bool UpdatePageImpl()
        {

            return true;
        }
        #endregion

        #region | Communication methods |
        public void ShowDetails()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
        }
        
        #region | Image binary control methods |
        public DEVICE_RESPONSE InsertBinaryImage(ushort imageIndex, string path)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            VMSImagePackage imgBinaryData = VMSImagePackage.FromFileWithIndex(imageIndex, path);
            
            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readResult = 0;
                bool sentOK = false;

                LOG(MethodBase.GetCurrentMethod().Name,"Sending  update data request...", LOG_LEVEL.INFO);
                // Prepare data
                byte[] data = new byte[2];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_SERVER_DATA_UPDATE_REQ;
                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_SERVER_DATA_UPDATE_REQ)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes"
                        + "\n   TAG: " + receivedBuffer[0]
                        + "\n   COMMAND: " + receivedBuffer[1], LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                LOG(MethodBase.GetCurrentMethod().Name, "Sending  update data info...", LOG_LEVEL.INFO);
                bWriter.Write(XORCryptor.Encrypt(imgBinaryData.Info.Data));
                Thread.Sleep(20);
                // read for response
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();
                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.DATA_INFO_HEADER)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes", LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                LOG(MethodBase.GetCurrentMethod().Name, "Sent  update data info", LOG_LEVEL.INFO);
                _client.SendBufferSize = 1024;

                for (int i = 0; i < imgBinaryData.Pakages.Count; i++)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Sending update data package " + i, LOG_LEVEL.INFO);
                    // Prepare buffer data
                    byte crc = CRCChecksum.ComputeChecksum(imgBinaryData.Pakages[i].Data);
                    byte[] outBuf = new byte[imgBinaryData.Pakages[i].Data.Length + 1];
                    Array.Copy(imgBinaryData.Pakages[i].Data, 0, outBuf, 0, imgBinaryData.Pakages[i].Data.Length);
                    // Add checksum byte
                    outBuf[imgBinaryData.Pakages[i].Data.Length] = crc;
                    // Write data
                    bWriter.Write(XORCryptor.Encrypt(outBuf));
                    Thread.Sleep(20); // delay
                    // Read data
                    readResult = bReader.Read(receivedBuffer, 0, 3);
                    bReader.BaseStream.Flush();
                    if (//receivedBuffer.Length == 3 &&
                        readResult == 3 &&
                        receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                        receivedBuffer[1] == (byte)COMMAND.DATA_PACKAGE_HEADER)
                    {
                        switch (receivedBuffer[2])
                        {
                            case (byte)DEVICE_RESPONSE.SUCCESS:
                                sentOK = true;
                                break;
                            case (byte)DEVICE_RESPONSE.ERROR:
                            default:
                                sentOK = false;
                                break;
                        }
                        LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                        if (!sentOK)
                            break;
                    }
                    else
                    {
                        // Process error here
                        LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes", LOG_LEVEL.ERROR);
                        break;
                    }
                }
                LOG(MethodBase.GetCurrentMethod().Name, "Insert image successfull", LOG_LEVEL.INFO);
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
            return DEVICE_RESPONSE.SUCCESS;
        }

        public DEVICE_RESPONSE DeleteBinaryImage(ushort imageIndex)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readResult = 0;
                bool sentOK = false;

                // Prepare data
                ushort bufSize = 4;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_DELETE_IMAGE;
                //BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
                BitConverter.GetBytes((ushort)imageIndex).CopyTo(data, 2);

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_DELETE_IMAGE)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);

                    return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes"
                        + "\n   TAG: " + receivedBuffer[0]
                        + "\n   COMMAND: " + receivedBuffer[1], LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE DeleteAllBinaryImage()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            return SendControlCommand(COMMAND.CMD_DELETE_ALL_IMAGE);
        }

        public ushort[] GetListImageIndex()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return null;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_GET_LIST_IMAGE_INDEX;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, receivedBuffer.Length);
                
                bReader.BaseStream.Flush();

                if (readCount > 2 && readCount % 2 == 0 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_GET_LIST_IMAGE_INDEX)
                {
                    ushort[] listIndex = new ushort[readCount / 2 - 1];
                    System.Buffer.BlockCopy(receivedBuffer, 2, listIndex, 0,readCount - 2);
                    string hex = "";
                    bool flag = true;
                    ushort imageCount = 0;
                    foreach (ushort u in listIndex)
                    {
                        if (flag)
                        {
                            imageCount = u;
                            flag = false;
                            continue;
                        }
                        hex += u + ", ";
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device images count: " + imageCount + "\n" + hex, LOG_LEVEL.DEBUG);

                    return listIndex;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: " + receivedBuffer[0] +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + receivedBuffer[1] +
                            " ===> Expected:  CMD_GET_LIST_IMAGE_INDEX(" +
                            COMMAND.CMD_GET_LIST_IMAGE_INDEX + ")",
                        LOG_LEVEL.ERROR);
                    return null;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return null;
            }
        }

        #endregion

        #region | Page Control |
        public void DumpLayout(string xmlpath)
        {
            FileStream fs = null;
            try
            {
                // Serialize the order to a file.   
                XmlSerializer serializer = new XmlSerializer(typeof(VMSLayout));

                // Deserialize data from xml
                fs = new FileStream(xmlpath, FileMode.Open);
                VMSLayout layout = (VMSLayout)serializer.Deserialize(fs);
                File.WriteAllBytes(Path.GetFileNameWithoutExtension(xmlpath) + ".dump", layout.getBytes());
                fs.Close();
                return;
            }
            catch (Exception e)
            {
                if (fs != null)
                    fs.Close();
                LogException(e);
                return;
            }
        }

        public DEVICE_RESPONSE CreatePageFromFile(string xmlpath)
        {
            FileStream fs = null;
            try
            {
                // Serialize the order to a file.   
                XmlSerializer serializer = new XmlSerializer(typeof(VMSLayout));

                // Deserialize data from xml
                fs = new FileStream(xmlpath, FileMode.Open);
                VMSLayout layout = (VMSLayout)serializer.Deserialize(fs);
                fs.Close();
                return CreatePage(layout);
            }
            catch (Exception e)
            {
                if (fs != null)
                    fs.Close();
                LogException(e);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE CreatePage(VMSLayout page)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (page == null)
            {
                LOG(MethodBase.GetCurrentMethod().Name, "null layout", LOG_LEVEL.ERROR);
                return DEVICE_RESPONSE.ERROR;
            }

            // prepare page data
            byte[] layoutBuf = page.getBytes();
            File.WriteAllBytes("out.buf", layoutBuf); //return DEVICE_RESPONSE.ERROR;
            byte[] data = new byte[4 + layoutBuf.Length];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_CREATE_PAGE;
            BitConverter.GetBytes((ushort)layoutBuf.Length).CopyTo(data, 2);
            layoutBuf.CopyTo(data, 4);

            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE UpdatePage(ushort pageID, VMSLayout page)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (page == null)
            {
                LOG(MethodBase.GetCurrentMethod().Name, "null layout", LOG_LEVEL.ERROR);
                return DEVICE_RESPONSE.ERROR;
            }

            // prepare page data
            byte[] layoutBuf = page.getBytes();
            byte[] data = new byte[6 + layoutBuf.Length];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_UPDATE_PAGE;
            BitConverter.GetBytes((ushort)layoutBuf.Length).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            layoutBuf.CopyTo(data, 6);

            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE DeletePage(ushort pageID)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            byte[] data = new byte[4];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_DELETE_PAGE;
            BitConverter.GetBytes(pageID).CopyTo(data, 2);
            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE GetPageInfo(ushort pageID /*out VMSLayout pageInfo*/)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            if (!DeviceReady())
            {
                //pageInfo = null;
                return DEVICE_RESPONSE.ERROR;
            }
            VMSLayout page = null;
            try
            {
                _client.SendTimeout = PACKAGE_TIMEOUT;
                _client.ReceiveTimeout = PACKAGE_TIMEOUT;
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                byte[] data = new byte[6];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_GET_PAGE_INFO;
                BitConverter.GetBytes((ushort)6).CopyTo(data, 2);
                BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
                bReader.BaseStream.Flush();
                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(200);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, receivedBuffer.Length);

                bReader.BaseStream.Flush();
                Console.WriteLine("Read count: " + readCount);
                if (readCount > 2 && 
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_GET_PAGE_INFO)
                {
                    page = new VMSLayout(receivedBuffer);
                    if (page != null)
                    {
                        LOG(MethodBase.GetCurrentMethod().Name, "Page Info: " + page.ToString(), LOG_LEVEL.DEBUG);

                        return DEVICE_RESPONSE.SUCCESS;
                    }
                    else
                        return DEVICE_RESPONSE.ERROR;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                            " ===> Expected:  " + COMMAND.CMD_GET_PAGE_INFO + "(0x" +
                            ((byte)COMMAND.CMD_GET_PAGE_INFO).ToString("X2") + ")",
                        LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE ActivePage(ushort pageID)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            byte[] data = new byte[4];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_SET_ACTIVE_PAGE;
            BitConverter.GetBytes(pageID).CopyTo(data, 2);
            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE GetActivePage()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            if (!DeviceReady())
            {
                //pageInfo = null;
                return DEVICE_RESPONSE.ERROR;
            }
            VMSLayout page = null;
            try
            {
                _client.SendTimeout = PACKAGE_TIMEOUT;
                _client.ReceiveTimeout = PACKAGE_TIMEOUT;
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                byte[] data = new byte[2];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_GET_ACTIVE_PAGE;
                
                bReader.BaseStream.Flush();
                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(200);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, receivedBuffer.Length);

                bReader.BaseStream.Flush();
                Console.WriteLine("Read count: " + readCount);
                if (readCount > 2 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_GET_ACTIVE_PAGE)
                {
                    ushort activePage = (ushort)BitConverter.ToInt16(receivedBuffer, 2);
                    
                    {
                        LOG(MethodBase.GetCurrentMethod().Name, "Active page: " + activePage, LOG_LEVEL.DEBUG);

                        return DEVICE_RESPONSE.SUCCESS;
                    }
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                            " ===> Expected:  " + COMMAND.CMD_GET_ACTIVE_PAGE + "(0x" +
                            ((byte)COMMAND.CMD_GET_ACTIVE_PAGE).ToString("X2") + ")",
                        LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        #endregion

        #region | Popup control |
        public DEVICE_RESPONSE InsertPopup(ushort pageID, ushort popupID, string xmlpath)
        {
            FileStream fs = null;
            try
            {
                // Serialize the order to a file.   
                XmlSerializer serializer = new XmlSerializer(typeof(VmsPopup));

                // Deserialize data from xml
                fs = new FileStream(xmlpath, FileMode.Open);
                VmsPopup popup = (VmsPopup)serializer.Deserialize(fs);
                fs.Close();
                return InsertPopup(pageID, popupID, popup);
            }
            catch (Exception e)
            {
                if (fs != null)
                    fs.Close();
                LogException(e);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE InsertPopup(ushort pageID, ushort popupID, VmsPopup popupData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            byte[] tempBuf = popupData.getBytes();
            ushort bufSize = (ushort)(8 + tempBuf.Length);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_INSERT_POPUP;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            tempBuf.CopyTo(data, 8);

            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE UpdatePopup(ushort pageID, ushort popupID, string xmlpath)
        {
            FileStream fs = null;
            try
            {
                // Serialize the order to a file.   
                XmlSerializer serializer = new XmlSerializer(typeof(VmsPopup));

                // Deserialize data from xml
                fs = new FileStream(xmlpath, FileMode.Open);
                VmsPopup popup = (VmsPopup)serializer.Deserialize(fs);
                fs.Close();
                return UpdatePopup(pageID, popupID, popup);
            }
            catch (Exception e)
            {
                if (fs != null)
                    fs.Close();
                LogException(e);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE UpdatePopup(ushort pageID, ushort popupID, VmsPopup popupData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            byte[] tempBuf = popupData.getBytes();
            ushort bufSize = (ushort)(8 + tempBuf.Length);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_UPDATE_POPUP;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            tempBuf.CopyTo(data, 8);

            return SendCommandByData(data);
        }

        public DEVICE_RESPONSE DeletePopup(ushort pageID, ushort popupID)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            ushort bufSize = (ushort)(8);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_DELETE_POPUP;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            return SendCommandByData(data);
        }
        #endregion

        #region | Playlist control |
        /// <summary>
        /// Insert image to popup playlist 
        /// </summary>
        /// <param name="pageID">Page containts popup</param>
        /// <param name="popupID">Popup index to be updated</param>
        /// <param name="imageData">Image code on device</param>
        /// <returns>Return response code</returns>
        public DEVICE_RESPONSE InsertImageToPlaylist(ushort pageID, ushort popupID, VmsPopupImage imageData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            byte[] pBuf = imageData.getBytes();
            ushort bufSize = (ushort)(8 + pBuf.Length);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_INSERT_IMAGE_TO_PLAYLIST;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            imageData.getBytes().CopyTo(data, 8);

            // send buffer data
            return SendCommandByData(data);
        }

        /// <summary>
        /// Update image to popup playlist 
        /// </summary>
        /// <param name="pageID">Page containts popup</param>
        /// <param name="popupID">Popup index to be updated</param>
        /// <param name="playOrder">Image index in playlist</param>
        /// <param name="imageData">Image code on device</param>
        /// <returns>Return response code</returns>
        public DEVICE_RESPONSE UpdateImageToPlaylist(ushort pageID, ushort popupID, 
            byte playOrder, VmsPopupImage imageData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            byte[] pBuf = imageData.getBytes();
            ushort bufSize = (ushort)(9 + pBuf.Length);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_UPDATE_IMAGE_TO_PLAYLIST;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            BitConverter.GetBytes((byte)playOrder).CopyTo(data, 8);
            imageData.getBytes().CopyTo(data, 9);

            // send buffer data
            return SendCommandByData(data);
        }

        /// <summary>
        /// Delete one image from popup playlist
        /// </summary>
        /// <param name="pageID">Page containts popup playlist</param>
        /// <param name="popupID">popup id</param>
        /// <param name="playOrder">Image index in playlist</param>
        /// <returns>Return response code</returns>
        public DEVICE_RESPONSE DeleteImageFromPlaylistCmd(ushort pageID, ushort popupID, byte playOrder)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            ushort bufSize = (ushort)(9);
            byte[] data = new byte[bufSize];
            data[0] = (byte)COMMAND.SERVER_TAG;
            data[1] = (byte)COMMAND.CMD_DELETE_IMAGE_FROM_PLAYLIST;
            BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
            BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
            BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
            data[8] = playOrder;

            // send buffer data
            return SendCommandByData(data);
        }

        #endregion

        /*
        /// <summary>
        /// Update image to popup playlist 
        /// </summary>
        /// <param name="socket">Device socket</param>
        /// <param name="pageID">Page containts popup</param>
        /// <param name="popupID">Popup index to be updated</param>
        /// <param name="playOrder">Image index in playlist</param>
        /// <param name="imageData">Image code on device</param>
        /// <returns>Return true if success, error if there are any exceptions</returns>
        private bool SendUpdateImageCmd( ushort pageID, ushort popupID,
            byte playOrder, VmsPopupImage imageData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = (ushort)(9 + IMAGE.IMAGE_LENGTH);
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_UPDATE_IMAGE_TO_PLAYLIST;
                BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
                BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
                BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
                BitConverter.GetBytes((byte)playOrder).CopyTo(data, 8);
                imageData.getBytes().CopyTo(data, 9);

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (readCount == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_UPDATE_IMAGE_TO_PLAYLIST)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + 
                        (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);   
                    return receivedBuffer[2] == (byte)DEVICE_RESPONSE.SUCCESS;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, 
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" + 
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: " + receivedBuffer[0] + 
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + receivedBuffer[1] + 
                            " ===> Expected:  CMD_UPDATE_IMAGE_TO_PLAYLIST(" + 
                            COMMAND.CMD_UPDATE_IMAGE_TO_PLAYLIST + ")",
                        LOG_LEVEL.ERROR);
                    return false;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return false;
            }
        }
        //bool dataReceived = false;
          */
        /// <summary>
        /// Update popup of page
        /// </summary>
        /// <param name="socket">Device socket</param>
        /// <param name="pageID">Page containts popup</param>
        /// <param name="popupID">Popup index to be updated</param>
        /// <param name="popupData">Popup data</param>
        /// <returns>Return true if success, error if there are any exceptions</returns>
        public bool SendUpdatePopupCmd( ushort pageID, ushort popupID,
            VmsPopup popupData)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return false;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.Flush();
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 0;
                byte[] buff = popupData.getBytes();
                bufSize = (ushort)(8 + buff.Length);

                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_UPDATE_POPUP;
                BitConverter.GetBytes((ushort)bufSize).CopyTo(data, 2);
                BitConverter.GetBytes((ushort)pageID).CopyTo(data, 4);
                BitConverter.GetBytes((ushort)popupID).CopyTo(data, 6);
                buff.CopyTo(data, 8);

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (readCount == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_UPDATE_POPUP)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " +
                        (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    return receivedBuffer[2] == (byte)DEVICE_RESPONSE.SUCCESS;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: " + receivedBuffer[0] +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + receivedBuffer[1] +
                            " ===> Expected:  CMD_UPDATE_POPUP(" +
                            COMMAND.CMD_UPDATE_POPUP + ")",
                        LOG_LEVEL.ERROR);
                    return false;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return false;
            }
        }
        #endregion

        public DEVICE_RESPONSE CaptureScreen()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            try
            {
                NetworkStream stream = _client.GetStream();
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_CAPTURE_SCREEN;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (readCount == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_CAPTURE_SCREEN)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " +
                        (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    ProcessError(readCount, receivedBuffer, COMMAND.CMD_CAPTURE_SCREEN);

                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
            
        }

        private void ProcessError(int readCount,byte[] buf,COMMAND expectedCmd)
        {
            LOG(MethodBase.GetCurrentMethod().Name,
                        "Device response wrong data:  " +
                        "\n   ReadCount: " + readCount + "bytes" +
                        " ===> Expected: 3 bytes" +
                        "\n   TAG: 0x" + buf[0].ToString("X2") +
                        " ===> Expected:  DEVICE_TAG(0x01)" +
                        "\n   COMMAND: " + buf[1].ToString("X2") +
                        " ===> Expected:  " + expectedCmd + "(0x" +
                        ((byte)expectedCmd).ToString("X2") + ")",
                    LOG_LEVEL.ERROR);
        }

        private DEVICE_RESPONSE SendControlCommand(COMMAND command)
        {
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.ReadTimeout = PACKAGE_TIMEOUT;
                stream.WriteTimeout = PACKAGE_TIMEOUT;
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)command;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (readCount == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)command)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " +
                        (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here

                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                            " ===> Expected:  " + command + "(0x" +
                            ((byte)command).ToString("X2") + ")",
                        LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        private DEVICE_RESPONSE SendCommandByData(byte[] data)
        {
            if (!DeviceReady() || data == null || data.Length <=2 ||
                data[0] != (byte)COMMAND.SERVER_TAG) return DEVICE_RESPONSE.ERROR;

            COMMAND command = (COMMAND)data[1];
            try
            {
                NetworkStream stream = _client.GetStream();
                _client.SendTimeout = PACKAGE_TIMEOUT;
                _client.ReceiveTimeout = PACKAGE_TIMEOUT;
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }

                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                // no need to prepare

                // Send the message to the connected TcpServer. 
                
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, 3);

                bReader.BaseStream.Flush();

                if (readCount == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)command)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " +
                        (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                            " ===> Expected:  " + command + "(0x" +
                            ((byte)command).ToString("X2") + ")",
                        LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE CheckLed()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            return SendControlCommand(COMMAND.CMD_CHECK_LED);
        }

        public DEVICE_RESPONSE ClearScreen()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            return SendControlCommand(COMMAND.CMD_CLEAR_LED);
        }

        public DEVICE_RESPONSE Reboot()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);

            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.ReadTimeout = PACKAGE_TIMEOUT;
                stream.WriteTimeout = PACKAGE_TIMEOUT;
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryWriter bWriter = new BinaryWriter(stream);

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_REBOOT;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                return DEVICE_RESPONSE.SUCCESS;
            }
            catch (Exception e)
            {
                LogException(e);
                return DEVICE_RESPONSE.ERROR;
            }
        }

        public DEVICE_RESPONSE ScanLed()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            return SendControlCommand(COMMAND.CMD_SCAN_LED);
        }

        public DEVICE_RESPONSE UpdateFirmware(string path)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            BlackboxFirmware frm = new BlackboxFirmware(path);

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.ReadTimeout = 60000;//PACKAGE_TIMEOUT;
                stream.WriteTimeout = 60000;//PACKAGE_TIMEOUT;

                stream.Flush();
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readResult = 0;
                bool sentOK = false;

                LOG(MethodBase.GetCurrentMethod().Name, "Sending  update firmware request...", LOG_LEVEL.INFO);
                // Prepare data
                byte[] data = new byte[2];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_SERVER_FIRMWARE_UPDATE_REQ;
                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_SERVER_FIRMWARE_UPDATE_REQ)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes"
                        + "\n   TAG: " + receivedBuffer[0]
                        + "\n   COMMAND: " + receivedBuffer[1], LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                LOG(MethodBase.GetCurrentMethod().Name, "Sending  firmware info...", LOG_LEVEL.INFO);
                bWriter.Write(XORCryptor.Encrypt(frm.Info.Data));
                Thread.Sleep(20);
                // read for response
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();
                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.FIRMWARE_INFO_HEADER)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes", LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                LOG(MethodBase.GetCurrentMethod().Name, "Sent  firmware info", LOG_LEVEL.INFO);
                _client.SendBufferSize = 1024;

                int nTry = 3;
                int temp = 0;
                for (int i = 0; i < frm.Pakages.Count; i++)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Sending firmware package " + i, LOG_LEVEL.INFO);
                    // Prepare buffer data
                    byte crc = CRCChecksum.ComputeChecksum(frm.Pakages[i].Data);
                    byte[] outBuf = new byte[frm.Pakages[i].Data.Length + 1];
                    Array.Copy(frm.Pakages[i].Data, 0, outBuf, 0, frm.Pakages[i].Data.Length);
                    // Add checksum byte
                    outBuf[frm.Pakages[i].Data.Length] = crc;

                    temp = nTry;
                    sentOK = false;
                    while (!sentOK)
                    {
                        if (temp <= 0)
                            break;

                        try
                        {
                            // Write data
                            bWriter.Write(XORCryptor.Encrypt(outBuf));
                            Thread.Sleep(20); // delay
                            // Read data
                            readResult = bReader.Read(receivedBuffer, 0, 3);
                            bReader.BaseStream.Flush();
                            if (//receivedBuffer.Length == 3 &&
                                readResult == 3 &&
                                receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                                receivedBuffer[1] == (byte)COMMAND.FIRMWARE_PACKAGE_HEADER)
                            {
                                switch (receivedBuffer[2])
                                {
                                    case (byte)DEVICE_RESPONSE.SUCCESS:
                                        sentOK = true;
                                        break;
                                    case (byte)DEVICE_RESPONSE.ERROR:
                                    default:
                                        sentOK = false;
                                        break;
                                }
                                LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                                temp--;
                                if (sentOK)
                                    break;
                            }
                            else
                            {
                                sentOK = false;
                                temp--;
                                // Process error here
                                LOG(MethodBase.GetCurrentMethod().Name,
                                    "Device response wrong data:  " +
                                    "\n   ReadCount: " + readResult + "bytes" +
                                    " ===> Expected: 3 bytes" +
                                    "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                                    " ===> Expected:  DEVICE_TAG(0x01)" +
                                    "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                                    " ===> Expected:  " + COMMAND.FIRMWARE_PACKAGE_HEADER + "(0x" +
                                    ((byte)COMMAND.FIRMWARE_PACKAGE_HEADER).ToString("X2") + ")",
                                LOG_LEVEL.ERROR);
                                break;
                            }
                        }
                        catch (System.Exception ex)
                        {
                            sentOK = false;
                            temp--;
                        }
                        
                    }
                }
                if (temp >= 0)
                    LOG(MethodBase.GetCurrentMethod().Name, "Update firmware successfull", LOG_LEVEL.INFO);
                else
                    LOG(MethodBase.GetCurrentMethod().Name, "Update firmware failed", LOG_LEVEL.INFO);
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
            return DEVICE_RESPONSE.SUCCESS;
        }

        public DEVICE_RESPONSE UpdateFont(string path)
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return DEVICE_RESPONSE.ERROR;

            FontFirmware frm = new FontFirmware(path);

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.ReadTimeout = 60000;//PACKAGE_TIMEOUT;
                stream.WriteTimeout = 60000;//PACKAGE_TIMEOUT;

                stream.Flush();
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readResult = 0;
                bool sentOK = false;

                LOG(MethodBase.GetCurrentMethod().Name, "Sending  update font request...", LOG_LEVEL.INFO);
                // Prepare data
                byte[] data = new byte[2];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.CMD_SERVER_FONT_UPDATE_REQ;
                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();

                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.CMD_SERVER_FONT_UPDATE_REQ)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes"
                        + "\n   TAG: " + receivedBuffer[0]
                        + "\n   COMMAND: " + receivedBuffer[1], LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                LOG(MethodBase.GetCurrentMethod().Name, "Sending  font info...", LOG_LEVEL.INFO);
                bWriter.Write(XORCryptor.Encrypt(frm.Info.Data));
                Thread.Sleep(20);
                // read for response
                readResult = bReader.Read(receivedBuffer, 0, 3);
                bReader.BaseStream.Flush();
                if (//receivedBuffer.Length == 3 &&
                    readResult == 3 &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.FONT_INFO_HEADER)
                {
                    switch (receivedBuffer[2])
                    {
                        case (byte)DEVICE_RESPONSE.SUCCESS:
                            sentOK = true;
                            break;
                        case (byte)DEVICE_RESPONSE.ERROR:
                        default:
                            sentOK = false;
                            break;
                    }
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG);
                    if (!sentOK)
                        return (DEVICE_RESPONSE)receivedBuffer[2];
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name, "Device response too much data:  " + readResult + "bytes", LOG_LEVEL.ERROR);
                    return DEVICE_RESPONSE.ERROR;
                }

                _client.SendBufferSize = 1024;

                int nTry = 3;
                int temp = 0;
                for (int i = 0; i < frm.Pakages.Count; i++)
                {
                    LOG(MethodBase.GetCurrentMethod().Name, "Sending firmware package " + i, LOG_LEVEL.INFO,false);
                    // Prepare buffer data
                    byte crc = CRCChecksum.ComputeChecksum(frm.Pakages[i].Data);
                    byte[] outBuf = new byte[frm.Pakages[i].Data.Length + 1];
                    Array.Copy(frm.Pakages[i].Data, 0, outBuf, 0, frm.Pakages[i].Data.Length);
                    // Add checksum byte
                    outBuf[frm.Pakages[i].Data.Length] = crc;

                    temp = nTry;
                    sentOK = false;
                    while (!sentOK)
                    {
                        if (temp <= 0)
                            break;

                        try
                        {
                            // Write data
                            bWriter.Write(XORCryptor.Encrypt(outBuf));
                            Thread.Sleep(20); // delay
                            // Read data
                            readResult = bReader.Read(receivedBuffer, 0, 3);
                            bReader.BaseStream.Flush();
                            if (//receivedBuffer.Length == 3 &&
                                readResult == 3 &&
                                receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                                receivedBuffer[1] == (byte)COMMAND.FONT_PACKAGE_HEADER)
                            {
                                switch (receivedBuffer[2])
                                {
                                    case (byte)DEVICE_RESPONSE.SUCCESS:
                                        sentOK = true;
                                        break;
                                    case (byte)DEVICE_RESPONSE.ERROR:
                                    default:
                                        sentOK = false;
                                        break;
                                }
                                LOG(MethodBase.GetCurrentMethod().Name, "Sending firmware package " + i +
                                    " Device response: " + (DEVICE_RESPONSE)receivedBuffer[2], LOG_LEVEL.DEBUG,false);
                                temp--;
                                if (sentOK)
                                    break;
                            }
                            else
                            {
                                sentOK = false;
                                temp--;
                                // Process error here
                                LOG(MethodBase.GetCurrentMethod().Name,"Sending firmware package " + i +
                                    " Device response wrong data:  " +
                                    "\n   ReadCount: " + readResult + "bytes" +
                                    " ===> Expected: 3 bytes" +
                                    "\n   TAG: 0x" + (receivedBuffer[0]).ToString("X2") +
                                    " ===> Expected:  DEVICE_TAG(0x01)" +
                                    "\n   COMMAND: " + (receivedBuffer[1]).ToString("X2") +
                                    " ===> Expected:  " + COMMAND.FONT_PACKAGE_HEADER + "(0x" +
                                    ((byte)COMMAND.FONT_PACKAGE_HEADER).ToString("X2") + ")",
                                LOG_LEVEL.ERROR,false);
                                break;
                            }
                        }
                        catch (System.Exception ex)
                        {
                            sentOK = false;
                            temp--;
                        }

                    }
                }
                if (temp >= 0)
                    LOG(MethodBase.GetCurrentMethod().Name, "Update font successfull", LOG_LEVEL.INFO);
                else
                    LOG(MethodBase.GetCurrentMethod().Name, "Update font failed", LOG_LEVEL.INFO);
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return DEVICE_RESPONSE.ERROR;
            }
            return DEVICE_RESPONSE.SUCCESS;
        }

        public ushort GetVersion()
        {
            LOG(MethodBase.GetCurrentMethod().Name, "", LOG_LEVEL.INFO);
            if (!DeviceReady()) return 0;

            try
            {
                NetworkStream stream = _client.GetStream();
                stream.ReadTimeout = PACKAGE_TIMEOUT;
                stream.WriteTimeout = PACKAGE_TIMEOUT;

                stream.Flush();
                var buffer = new byte[4096];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
                BinaryReader bReader = new BinaryReader(stream);
                BinaryWriter bWriter = new BinaryWriter(stream);

                byte[] receivedBuffer = new byte[1024];
                int readCount = 0;

                // Prepare data
                ushort bufSize = 2;
                byte[] data = new byte[bufSize];
                data[0] = (byte)COMMAND.SERVER_TAG;
                data[1] = (byte)COMMAND.GET_VERSION;

                // Send the message to the connected TcpServer. 
                bWriter.Write(XORCryptor.Encrypt(data));
                Thread.Sleep(20);
                // Read response from device
                readCount = bReader.Read(receivedBuffer, 0, receivedBuffer.Length);

                bReader.BaseStream.Flush();

                if (readCount == 4       &&
                    receivedBuffer[0] == (byte)COMMAND.DEVICE_TAG &&
                    receivedBuffer[1] == (byte)COMMAND.GET_VERSION)
                {
                    ushort version = BitConverter.ToUInt16(receivedBuffer, 2);
                    LOG(MethodBase.GetCurrentMethod().Name, "Device firnware version: " + version, LOG_LEVEL.DEBUG);

                    return version;
                }
                else
                {
                    // Process error here
                    LOG(MethodBase.GetCurrentMethod().Name,
                            "Device response wrong data:  " +
                            "\n   ReadCount: " + readCount + "bytes" +
                            " ===> Expected: 3 bytes" +
                            "\n   TAG: " + receivedBuffer[0] +
                            " ===> Expected:  DEVICE_TAG(0x01)" +
                            "\n   COMMAND: " + receivedBuffer[1].ToString("X2") +
                            " ===> Expected:  CMD_GET_LIST_IMAGE_INDEX(" +
                            (byte)COMMAND.CMD_GET_LIST_IMAGE_INDEX + ")",
                        LOG_LEVEL.ERROR);
                    return 0;
                }
            }
            catch (System.Exception ex)
            {
                LogException(ex);
                return 0;
            }
        }
    }
}
